package com.gem.netty.message.robot;

import com.gem.entity.Card;
import com.gem.entity.Game;
import com.gem.entity.Gem;
import com.gem.enums.*;
import com.gem.factory.game.GameFactory;
import com.gem.holder.ThreadLocalFactory;
import com.gem.netty.entity.CardInfo;
import com.gem.netty.entity.ClientContent;
import com.gem.netty.entity.Content;
import com.gem.netty.entity.CurrentUser;
import com.gem.netty.message.swap.AbstractSwapBase;
import com.gem.netty.message.swap.GetCard;
import com.gem.netty.session.GroupSessionFactory;
import com.gem.utils.R;
import io.netty.channel.Channel;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Author: Xhy
 * CreateTime: 2023-02-06 17:51
 * 机器人回合
 */
public class RobotRound {

    public static void RobotRound(CurrentUser robot, Game game)  {

        // 机器人段位 TODO
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Integer robotLevel = robot.getRobotLevel();
        String roomId = game.getRoomId();
        try {
            if (robotLevel == 0){
                noviceRobot(robot,game);
            }else {

            }
        }catch (Exception e){
            List<Channel> channels = GroupSessionFactory.getGroupSession().getMembersChannel(roomId);
            // 修改用户当前回合状态
            setRoundEndState(robot);
            GameFactory.roundStage(roomId);
            GameFactory.notifyUsers(channels, R.ok().data("color", MessageColorType.GET_GEM.type)
                    .message(robot.getName()+"机器人出故障了").type(ClientMessageType.GET_GEM.type),roomId);
            return;
        }


        /**
         * 换贵族
         */
    }

    /**
     * 拿宝石。
     * 策略：
     * 1.拥有卡牌buff+宝石 = 自身拥有宝石
     * 2.场上卡牌-自身拥有宝石 = 一些卡牌
     * 3.对于卡牌进行排序：最少兑换宝石数量排序。数量相同，分数排序
     * 4.根据拿取宝石策略尝试换取卡牌
     */
    private static void noviceRobot(CurrentUser robot, Game game){
        String robotId = robot.getId();
        // 1.计算机器人拥有的宝石
        int[] robotOwnGems = new int[7];
        TreeMap<Integer, Integer> robotGems = robot.getGems();
        TreeMap<Integer, List<Card>> cards = robot.getCards();
        robotGems.forEach((k,v)->{
            robotOwnGems[k] = v;
        });
        cards.forEach((k,v)->{
            robotOwnGems[k]+=v.size();
        });
        // 2.获取场上的牌并且清洗
        // 装有需要宝石数量小于4并且按照高分数优先排列的卡牌
        PriorityQueue<Card> rinseCards = new PriorityQueue<>(new Comparator<Card>() {
            @Override
            public int compare(Card o1, Card o2) {

                return o1.getResidue() == o2.getResidue() ? -(o1.getScore() - o2.getScore()) : o1.getResidue() - o2.getResidue();
            }
        });
        Map<Integer, List<Card>> showCards = game.getShowCards();

        showCards.forEach((k,v)->{
            for (Card card : v) {
                Map<Integer, Integer> needGems = card.getGems();
                int residue = 0;
                for (Map.Entry<Integer, Integer> entry : needGems.entrySet()) {
                    // 卡牌需要的宝石-自身拥有的宝石
                    int t = entry.getValue() - robotOwnGems[entry.getKey()];
                    residue+=  t< 0 ? 0 : t;
                    // 计算卡牌还需要多少个宝石:不用在意需要宝石的类型。只在意数量：后续用于排序出来
                }
                if (residue <= 3){
                    card.setResidue(residue);
                    rinseCards.add(card);
                }
            }
        });
        /**
         * rinseCards 为空说明为开局,则要根据一级卡牌选择策略。随机获取一级卡牌根据卡牌中的宝石来拿取宝石
         */
        String roomId = game.getRoomId();
        Map<Integer, Integer> showGems = game.getGems();


        if (ObjectUtils.isEmpty(rinseCards)){
            // 1.随机获取一级卡牌中的任意一张卡牌
            Card card = showCards.get(CardType.PRIMARY_CARD.type).get(0);

            // 2.根据获取的卡牌拿取宝石
            Map<Integer, Integer> needGems = card.getGems();

            // 3.判断卡牌中需要的宝石策略,需要3个类型的宝石则3个都拿，如果只要2个宝石，则各拿一个并且结束
            // getGems :存储宝石类型 元素为1
            int[] getGems = new int[needGems.size()];
            AtomicInteger index = new AtomicInteger(0);
            needGems.forEach((k,v)->{
                getGems[index.get()] = k;
                index.getAndIncrement();
            });


            for (int getGem : getGems) {
                robotGems.put(getGem,robotGems.get(getGem)+1);
                showGems.put(getGem,showGems.get(getGem)-1);
            }

        }else {
            List<Channel> channels = GroupSessionFactory.getGroupSession().getMembersChannel(roomId);
            // 3.尝试换取卡牌
            Card card = rinseCards.poll();
            if (!ObjectUtils.isEmpty(card)){
                AtomicInteger gemNumber = new AtomicInteger(3);
                // 当一张卡牌需要相同的2个宝石后为true
                AtomicBoolean flag = new AtomicBoolean(false);
                AtomicBoolean isSwap = new AtomicBoolean(true);
                // 需要拿取的宝石
                HashMap<Integer, Integer> needGetGems = new HashMap<>();
                for (int i = 1; i <= 5; i++) {
                    needGetGems.put(i,0);
                }


                   card.getGems().forEach((type,number)->{
                       // 自身拥有宝石 - 卡牌需要宝石
                       int t = (robotOwnGems[type] - number);
                       // 负数说明需要换，正数则i为0，有足够的宝石换取
                       int i =  t < 0 ? Math.abs(t) : 0;
                       /**
                        * 只要拿过2个宝石后，后面就不能再拿宝石
                        * 1. i > 2 尝试拿取2个相同的
                        * 2. i == 1 是否之前已经拿过2个宝石,拿取宝石库对应宝石，没有该宝石 pass
                        * 3. i== 2 修改state为true，后续不能在拿宝石
                        */
                       if (i!=0){
                           int numbers = game.getUsers().size();

                           if (i > 2 && gemNumber.get()==3){
                               // 宝石库是否大于人数数量
                               if (showGems.get(type) > numbers){
                                   needGetGems.put(type,needGetGems.get(type)+2);
                                   return;
                               }else {
                                   needGetGems.put(type,needGetGems.get(type)+1);
                                   gemNumber.getAndDecrement();
                               }
                               isSwap.set(false);
                               return;
                           }else if (i == 1 || i ==2){
                               if (flag.get()){
                                   return;
                               }
                               if (i==1){
                                   // 查询宝石库是否有对应宝石
                                   if (showGems.get(type) == 0){
                                       return;
                                   }
                                   needGetGems.put(type,needGetGems.get(type)+1);
                                   gemNumber.getAndDecrement();
                               }else {
                                   // 可能出现之前拿过一个宝石，这次需要用2个宝石拿
                                   if (gemNumber.get() <=2){
                                       return;
                                   }
                                   // 根据房间内的人数查询宝石库是否有对应宝石
                                   if (showGems.get(type) <= numbers){
                                       isSwap.set(false);
                                       return;
                                   }
                                   needGetGems.put(type,needGetGems.get(type)+2);
                                   flag.set(true);
                                   return;
                               }
                           }
                       }

                   });




                if (isSwap.get()){
                    // 拿宝石
                    needGetGems.forEach((type,number)->{
                        for (int i = 0; i < number; i++) {
                            GameFactory.notifyUsers(channels, R.ok().data("color", MessageColorType.GET_GEM.type)
                                    .message(robot.getName()+" 拿取:"+ Gem.getGemInfo(type)).type(ClientMessageType.GET_GEM.type),roomId);
                            robotGems.put(type,robotGems.get(type)+1);
                            reduceGameInGem(game,type);
                            robot.setGetGemNumber(robot.getGetGemNumber()+1);
                        }
                    });

                }
            }


            // 换卡牌
            ClientContent content = new ClientContent();
            content.setRoomId(roomId);
            content.setSendId(robotId);
            content.setType(ClientMessageType.GET_CARD.type);
            Content c = new Content();
            c.setId(robotId);
            CardInfo cardInfo = new CardInfo();
            cardInfo.setNo(card.getNo());
            // 填充机器人使用的宝石
            cardInfo.setGems(new HashMap<>(robotGems));
            cardInfo.setScore(card.getScore());
            cardInfo.setCardBuff(card.getCardBuff());
            cardInfo.setType(card.getType());
            HashMap<Integer, Integer> needBuff = new HashMap<>();
            cards.forEach((k,v)->{
                needBuff.put(k,v.size());
            });
            cardInfo.setGemCards(needBuff);
            c.setCardInfo(cardInfo);
            content.setContent(c);
            robot.setState(GameRoundStageType.SWAP_CARD.type);
            swapCard(content,robot);
        }
        // 修改用户当前回合状态
        setRoundEndState(robot);
        GameFactory.roundStage(roomId);

    }

    private static void swapCard(ClientContent content,CurrentUser robot){

        AbstractSwapBase getCard = new GetCard();
        R r = getCard.doSwap(content);
        if (!r.getState()){
            return;
        }
        addGem(content);
        // 获取当前拿取卡牌信息
        Game game = GameFactory.get(content.getRoomId());
        robot.setCurrentGetCardInfo(content.getContent().getCardInfo());
        CardInfo cardInfo = robot.getCurrentGetCardInfo();
        // 将卡牌存入用户卡牌库
        addCard(game,content.getContent().getCardInfo());
        addScore(robot,cardInfo.getScore());
        reduceUserTotalGemSize(robot);

        // 清理卡牌库
        GameFactory.reduceGameCard(content,game);
        // 补牌
        GameFactory.getShowCard(game,content);
        // 告知其他用户
        String roomId = content.getRoomId();
        List<Channel> channels = GroupSessionFactory.getGroupSession().getMembersChannel(roomId);
        String userName = robot.getName();
        ThreadLocalFactory.remove();
        if (is15score(robot)){
            game.getWins().add(robot);
            GameFactory.notifyUsers(channels,R.ok()
                    .data("color", MessageColorType.SYSTEM_MESSAGE.type).message(userName +"这机器人有15分了!").type(ClientMessageType.GET_CARD.type),roomId);
        }
        GameFactory.notifyUsers(channels,R.ok().data("color",MessageColorType.GET_CARD.type).message(userName+" 换取卡牌: "+ CardType.getInfo(cardInfo.getType())
                +","+cardInfo.getScore()+" 分,卡牌buff为:"+GemType.get(cardInfo.getCardBuff()))
                .type(content.getType()),roomId);

    }



    private static boolean is15score(CurrentUser user) {
        return user.getOwnScore() >=15;
    }

    private static void setRoundEndState(CurrentUser user){
        user.setState(GameRoundStageType.WAIT.type);
    }

    private static void reduceUserTotalGemSize(CurrentUser user) {
        AtomicInteger number = new AtomicInteger(0);
        user.getGems().forEach((k,v)->{
            number.getAndAdd(v);
        });
        user.setGetGemNumber(number.get());
    }

    private static void addCard(Game game,CardInfo cardInfo){
        CurrentUser user = game.getUsers().get(game.getCurrentIndex());

        List<Card> cardList = game.getShowCards().get(cardInfo.getType());
        int i =0;
        for (; i < cardList.size() ; i++) {
            if (cardList.get(i).getNo() == cardInfo.getNo()){
                break;
            }
        }

        user.getCards().get(cardInfo.getCardBuff()).add(Card.getCard(cardInfo.getNo()));
    }

    // 宝石库补宝石
    private static void addGem(ClientContent content) {
        Game game = GameFactory.get(content.getRoomId());
        // 用需要的卡牌 - 使用的卡牌buff = 宝石库增加的数量
        CardInfo cardInfo = content.getContent().getCardInfo();
        Map<Integer, Integer> gemCards = cardInfo.getGemCards(); // 用户的Buff
        Map<Integer, Integer> swapCard = Card.getCardGems(cardInfo.getNo()); // 该卡需要宝石数
        Map<Integer,Integer> needAddGem = new HashMap<>();
        Map<Integer, Integer> replaceGems = cardInfo.getReplaceGems();
        swapCard.forEach((k,v)->{
            Integer goldK = replaceGems.get(k);
            goldK = goldK == null ? 0 : goldK;
            Integer gemCount = v - goldK;
            // buff数量
            Integer number = gemCards.get(k);
            if (number!=null){
                gemCount -= number;
            }
            needAddGem.put(k, gemCount);
        });
        Map<Integer, Integer> gems = game.getGems();
        // 玩家使用的宝石 - 替的宝石的  < 0 ? 0 :  玩家使用的宝石 - 替的宝石的
        needAddGem.forEach((k,v)->{
            gems.put(k,gems.get(k)+v );
        });

        // 纠错
        int numbers = game.getUsers().size();
        int limit = numbers == 2 ? 4 : numbers == 3 ? 5 : 7;
        gems.forEach((k,v)->{
            if (v > limit){
                gems.put(k,limit);
            }
        });
        // 是否用了黄金替宝石
        if (replaceGems.size() > 0){
            AtomicInteger number = new AtomicInteger(0);
            replaceGems.forEach((k,v)->{
                number.getAndAdd(v);
            });
            Object tsCard = ThreadLocalFactory.get("isTsCard");
            Boolean isTsCard = false;
            if (tsCard instanceof Boolean){
                isTsCard = (Boolean) tsCard;
            }
            if(isTsCard){
                number.getAndDecrement();
            }
            gems.put(GemType.GOLD.type,gems.get(GemType.GOLD.type)+number.get());
        }
    }

    /**
     * 宝石入库
     * @param user
     * @param gem
     */
    private static void putGem(CurrentUser user,Integer gem){
        Map<Integer, Integer> gems = user.getGems();
        // 是否拿的是黄金:加状态
        if (gem == 6){
            user.setTSFlag(true);
        }
        if (gems.containsKey(gem)){
            gems.put(gem,gems.get(gem)+1);
        }else {
            gems.put(gem,1);
        }
    }

    private static void reduceGameInGem(Game game,Integer currentGetGem){
        // 获取当前用户选择的宝石
        game.getGems().put(currentGetGem,game.getGems().get(currentGetGem)-1);
    }

    private static void addScore(CurrentUser user, Integer score) {
        user.setOwnScore(user.getOwnScore()+score);
    }
}
